# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: jaewon

import datetime
import functools

from coin.base.datetime_util import to_datetime
from coin.exchange.okex_futures.kr_rest.futures_product import (OkexFuturesProduct)
from coin.exchange.bitfinex_v2.kr_rest.product import BitfinexProduct
from coin.strategy.mm.simple_sim import result_util
from coin.strategy.mm.simple_sim.strategy.pass_unhedge_3 import (PassUnhedgedSimStrategy)
from coin.strategy.mm.simple_sim.profile.pass_unhedge_xbtusd_3 import (linear_sell_edge,
                                                                       linear_buy_edge)


def get_products():
  return [OkexFuturesProduct.FromStr('BTC-USDT.QUARTER'), BitfinexProduct.FromStr('BTC-USD')]


def get_machines():
  return ['feed-3.eu-west-1', 'feed-6.eu-west-1']


def get_time_ranges():
  ranges = []
  base_ts = datetime.datetime(2018, 4, 8, 0, 0, 0)
  for day_before in reversed(range(7)):
    from_ts = base_ts - datetime.timedelta(days=day_before)
    to_ts = from_ts + datetime.timedelta(hours=24)
    ranges.append((from_ts, to_ts))
  return ranges


def get_strategy(from_ts, to_ts):
  products = get_products()
  ref_product = products[0]
  ref_product_true_book_funcs = ((lambda book: book.get_notional_asks_by_qty(200.)[1][-1][0]),
                                 (lambda book: book.get_notional_bids_by_qty(200.)[1][-1][0]))

  pass_product = products[1]
  pass_product_true_book_funcs = ((lambda book: book.get_notional_asks_by_amt(10000.)[1][-1][0]),
                                  (lambda book: book.get_notional_bids_by_amt(10000.)[1][-1][0]))

  NS_PER_SECOND = (10**9)
  NS_PER_MINUTE = 60 * NS_PER_SECOND

  strategy_list = []

  for basis_ma_window in [5, 10, 15]:
    for edge_bp in [13, 15, 17, 19, 21]:
      close_edge_bp = edge_bp
      pricing_param = {
          'basis_ma_window': basis_ma_window * NS_PER_MINUTE,
          'tick': 0.1,
          'book_askt_func_1': ref_product_true_book_funcs[0],
          'book_bidt_func_1': ref_product_true_book_funcs[1],
          'book_askt_func_2': pass_product_true_book_funcs[0],
          'book_bidt_func_2': pass_product_true_book_funcs[1]
      }

      pass_executor_param = {
          'lot_size': 0.2,
          'min_pos': -1.,
          'max_pos': 1.,
          'maker_fee': 0 / 10000.,
          'taker_fee': 10. / 10000.,
          'execution_delay': 1 * NS_PER_SECOND,
          'post_only': True,
          'trade_qty_func': (lambda trade: trade.qty)
      }

      name = '%02dm.%02dbp.%s' % (basis_ma_window, edge_bp, to_datetime(from_ts).strftime('%Y%m%d'))

      strategy = PassUnhedgedSimStrategy(pass_product,
                                         ref_product,
                                         functools.partial(linear_sell_edge,
                                                           edge_bp / 10000.,
                                                           close_edge_bp / 10000.,
                                                           1.),
                                         functools.partial(linear_buy_edge,
                                                           edge_bp / 10000.,
                                                           close_edge_bp / 10000.,
                                                           1.),
                                         pricing_param,
                                         pass_executor_param,
                                         trade_after=basis_ma_window,
                                         feature_filepath=('out/feature.%s.csv' % name),
                                         fill_filepath=('out/fill.%s.csv' % name),
                                         name=name)
      strategy_list.append(strategy)

  return strategy_list


def get_strategy_result(strategy):
  return {'name': strategy.name, **strategy.get_summary()}


def aggregate_result(results):
  return result_util.aggregate_sim_result(results)
